﻿namespace AutoRevit.Entry.Command.Extends.HotUpdate;

/// <summary>
/// 热更新扩展处理
/// </summary>
internal class HotUpdateExtendHandler : IExtendHandler
{
    const string EXECUTE_METHOD_NAME = "Autodesk.Revit.UI.IExternalCommand.Execute";

    /// <summary>
    /// 处理
    /// </summary>
    /// <param name="revitData"></param>
    /// <param name="extend"></param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    public HandlerResult Execute(IRevitData revitData, object extend)
    {
        if (extend is not IHotUpdateExtend hotUpdateExtend || !hotUpdateExtend.CanUpdate || extend is not IExternalCommand command)
        {
            return new HandlerResult(true);
        }

        var currentType = command.GetType();
        var currentTypeAssemblieName = currentType.Assembly.GetName().Name;
        var currentTypeAssemblies = AppDomain.CurrentDomain.GetAssemblies().Where(t => t.GetName().Name == currentTypeAssemblieName).ToArray();

        if (currentTypeAssemblies.Length < 2)
            return new HandlerResult(true);

        var newTypeAssemblie = currentTypeAssemblies.Last();

        if (newTypeAssemblie == currentType.Assembly)
            return new HandlerResult(true);

        var newType = newTypeAssemblie.GetType(currentType.FullName!);

        if (newType == null)
            return new HandlerResult(true);

        var instance = newType.Assembly.CreateInstance(newType.FullName!);

        var flag = System.Reflection.BindingFlags.Public
                    | System.Reflection.BindingFlags.NonPublic
                    | System.Reflection.BindingFlags.Instance
                    | System.Reflection.BindingFlags.InvokeMethod;

        var ps = new object[] { revitData.CommandData, revitData.ResultMessage!, revitData.ElementSet };

        var executeMethod = newType.GetMethods(flag).Single(t => t.Name == EXECUTE_METHOD_NAME);

        var result = executeMethod!.Invoke(instance, ps);

        revitData.ResultMessage = ps[1]?.ToString();

        return new HandlerResult((Result)result!, false);
    }
}
